package com.ayu.shortlink.engine.service.impl;

import com.alibaba.fastjson2.JSON;
import com.ayu.shortlink.engine.common.constant.RedisCacheConstant;
import com.ayu.shortlink.engine.common.convention.exception.ClientException;
import com.ayu.shortlink.engine.common.enums.CouponHotRankEnum;
import com.ayu.shortlink.engine.dao.entity.CouponTemplateDO;
import com.ayu.shortlink.engine.dao.mapper.CouponTemplateMapper;
import com.ayu.shortlink.engine.service.CouponTemplateService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.redisson.Redisson;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static com.ayu.shortlink.engine.common.constant.RedisCacheConstant.COUPON_HOT_RANK_KEY;

@Service
@RequiredArgsConstructor
public class CouponTemplateServiceImpl extends ServiceImpl<CouponTemplateMapper, CouponTemplateDO> implements CouponTemplateService {
    private final CouponTemplateMapper couponTemplateMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final Redisson redisson;
    private final Lock lock = new ReentrantLock();

    @Override
    public List<CouponTemplateDO> findCouponTemplate(List<Long> couponTemplateIds, List<Long> shopNumberIds) {
        List<CouponTemplateDO> result = new ArrayList<>();

        for (int i = 0; i < couponTemplateIds.size(); i++) {
            LambdaQueryWrapper<CouponTemplateDO> queryWrapper = Wrappers.lambdaQuery(CouponTemplateDO.class)
                    .eq(CouponTemplateDO::getId, couponTemplateIds.get(i))
                    .eq(CouponTemplateDO::getShopNumber, shopNumberIds.get(i));
            CouponTemplateDO couponTemplateDO = couponTemplateMapper.selectOne(queryWrapper);

            if (couponTemplateDO != null){
                result.add(couponTemplateDO);
                // 把一些重要的元数据放进去即可 后续再通过元数据去查详细信息(减轻Redis的存储压力)
                CouponTemplateDO templateDO = CouponTemplateDO
                        .builder()
                        .id(couponTemplateDO.getId())
                        .shopNumber(couponTemplateDO.getShopNumber())
                        .name(couponTemplateDO.getName())
                        .build();

                stringRedisTemplate.opsForZSet().incrementScore("coupon:hot-rank",JSON.toJSONString(templateDO), CouponHotRankEnum.READ.getScore());
            }
        }
        return result;
    }

    @Override
    public CouponTemplateDO findCouponTemplateByIdAndShopNumber(String shopNumber, String couponTemplateId) {
        StringBuilder var = new StringBuilder()
                .append(shopNumber)
                .append("_")
                .append(couponTemplateId);
        String couponTemplateKey = String.format(RedisCacheConstant.COUPON_TEMPLATE_KEY, var);

        String jsonStr = stringRedisTemplate.opsForValue().get(couponTemplateKey);
        if(jsonStr != null) {
            //没有该信息
            if(jsonStr.equals("_")){
                throw new ClientException("没有该优惠券模版");
            }
            CouponTemplateDO couponTemplateDO = JSON.parseObject(jsonStr, CouponTemplateDO.class);
            // 把一些重要的元数据放进去即可 后续再通过元数据去查详细信息(减轻Redis的存储压力)
            CouponTemplateDO templateDO = CouponTemplateDO
                    .builder()
                    .id(couponTemplateDO.getId())
                    .shopNumber(couponTemplateDO.getShopNumber())
                    .name(couponTemplateDO.getName())
                    .build();

            stringRedisTemplate.opsForZSet().incrementScore(COUPON_HOT_RANK_KEY,JSON.toJSONString(templateDO), CouponHotRankEnum.READ.getScore());
            return couponTemplateDO;
        }

        lock.lock();
        CouponTemplateDO couponTemplate = null;
        try {
            //双重判定锁
            jsonStr = stringRedisTemplate.opsForValue().get(couponTemplateKey);
            if(jsonStr != null) {
                //没有该信息
                if(jsonStr.equals("_")){
                    throw new ClientException("没有该优惠券模版");
                }
                CouponTemplateDO couponTemplateDO = JSON.parseObject(jsonStr, CouponTemplateDO.class);
                // 把一些重要的元数据放进去即可 后续再通过元数据去查详细信息(减轻Redis的存储压力)
                CouponTemplateDO templateDO = CouponTemplateDO
                        .builder()
                        .id(couponTemplateDO.getId())
                        .shopNumber(couponTemplateDO.getShopNumber())
                        .name(couponTemplateDO.getName())
                        .build();

                stringRedisTemplate.opsForZSet().incrementScore(COUPON_HOT_RANK_KEY,JSON.toJSONString(templateDO), CouponHotRankEnum.READ.getScore());
                return couponTemplateDO;
            }

            LambdaQueryWrapper<CouponTemplateDO> queryWrapper = Wrappers.lambdaQuery(CouponTemplateDO.class)
                    .eq(CouponTemplateDO::getShopNumber, Long.parseLong(shopNumber))
                    .eq(CouponTemplateDO::getId, couponTemplateId);

            couponTemplate = couponTemplateMapper.selectOne(queryWrapper);

            if(couponTemplate == null){
                stringRedisTemplate.opsForValue().set(couponTemplateKey, "_");
                throw new ClientException("没有该优惠券模版");
            }else {
                // 设置过期时间为30分钟
                stringRedisTemplate.opsForValue().set(couponTemplateKey, JSON.toJSONString(couponTemplate),30, TimeUnit.MINUTES);
            }
        }finally {
            lock.unlock();
        }
        // 把一些重要的元数据放进去即可 后续再通过元数据去查详细信息(减轻Redis的存储压力)
        CouponTemplateDO templateDO = CouponTemplateDO
                .builder()
                .id(couponTemplate.getId())
                .shopNumber(couponTemplate.getShopNumber())
                .name(couponTemplate.getName())
                .build();

        stringRedisTemplate.opsForZSet().incrementScore(COUPON_HOT_RANK_KEY,JSON.toJSONString(templateDO), CouponHotRankEnum.READ.getScore());
        return couponTemplate;
    }

    @Override
    public List<CouponTemplateDO> findHotRank(Integer n) {
        if (n <= 0){
            throw new ClientException("参数错误");
        }
        Set<String> strings = stringRedisTemplate.opsForZSet().reverseRange(COUPON_HOT_RANK_KEY, 0, n - 1);

        List<CouponTemplateDO> resp = new ArrayList<>(strings.size());

        strings.forEach(item -> resp.add(JSON.parseObject(item, CouponTemplateDO.class)));
        return resp;
    }
}
